﻿using System;
using System.Linq;
using System.Threading.Tasks;
using System.Net;
using Sustainalytics.DataLayer.ConnectionStrings;
using Sustainalytics.Entities.ConnectionStrings;
using Sustainalytics.Utils;
using Sustainalytics.Utils.WebApi.ErrorCodes;
using System.Web.Http;
using System.Net.Http;
using System.Configuration;
using Sustainalytics.DataLayer;
using Sustainalytics.CarbonData.BussinesLogic;
using Sustainalytics.DataLayer.Shared;

namespace Sustainalytics.CarbonData.Service.Controllers
{
   
    [RoutePrefix("api/v1/inputfile")]
    [LogControllerFilter(true, true, false)]
    public class InputFileController: ApiController, IInputFileController
    {
        IFileRepository fileRepository; 
        ProductInvolvementEventSource log;
        FileUpload _fileUpload;

        public InputFileController()
        {
            try
            {
                var clientPlatformConnectionString = ConfigurationManager.ConnectionStrings["ClientPlatform"].ConnectionString;
                var connectionStringsManager = ConnectionStringsManager.GetInstance(ConnectionStringsRepository.GetInstance(clientPlatformConnectionString));
                
                var dwConnectionString = connectionStringsManager.GetConnectionString(ConnectionStringType.ClientDW);
                
                fileRepository = new FileRepository(clientPlatformConnectionString);
                var inputFileRepository = new RepositoryCollection<CarbonDataInputFile>(clientPlatformConnectionString);

                var updater = new ExcelFileImport(dwConnectionString);

                _fileUpload = new FileUpload(fileRepository, inputFileRepository, updater);

                log  = ProductInvolvementEventSource.Log;
            }
            catch(Exception ex)
            {
                log.Exception(ex);
                throw;
            }           
        }
     
        [Route("")]        
        public HttpResponseMessage Get()
        {
            return Get(Guid.Empty, true);
        }

        [Route("id")]        
        public HttpResponseMessage Get(Guid id, bool includeAllFields, bool getLatest = true)
        {
            var response = (HttpResponseMessage)null;
            try
            {
                if (getLatest)
                {
                    var file = _fileUpload.ReadLatestInputFileHistory();

                    if (file == null)
                        response = Request.CreateResponse(HttpStatusCode.NotFound); 
                    else
                        response = Request.CreateResponse(HttpStatusCode.OK, file); 
                }
                else
                {
                    response = Request.CreateResponse(HttpStatusCode.NotImplemented); 
                }
            }
            catch (Exception ex)
            {
                log.Exception(ex);
                response = Request.CreateResponse(HttpStatusCode.InternalServerError, 
                    new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException });
            }            
            return response;
        }

        [Route("")]
        public Task<HttpResponseMessage> Post()
        {
            try
            {
                // put the file in mongo
                var id = Guid.NewGuid();
                var filename    = Request.Content.Headers.ContentDisposition.FileName;
                if (filename.StartsWith("\""))
                    filename = filename.Substring(1);

                if (filename.EndsWith("\""))
                    filename = filename.Substring(0, filename.Length - 2);


                var contentType = Request.Content.Headers.ContentType.ToString();
                var mongoData   = fileRepository.NewFile(id, filename, contentType);

                log.UploadFiles(filename, contentType, id);

                var result = Request.Content.ReadAsStreamAsync()
                    .ContinueWith(task =>
                    {

                        if (task.IsCanceled || task.IsFaulted)
                            throw new HttpRequestException();

                        try
                        {
                            using (mongoData.Item1)
                            {
                                task.Result.CopyTo(mongoData.Item1);


                                ValidationResult vResult;
                                var inputFile = _fileUpload.CreateAndValidateInputFile(mongoData.Item2, mongoData.Item1,
                                    filename, out vResult);

                                var isValid = false;
                                var details = "Validation failure";

                                var newest = inputFile.History.LastOrDefault();

                                if (newest != null)
                                {
                                    isValid = (newest.Status == UploadStatus.UploadValid);
                                    details = newest.Details;
                                }

                                return Request.CreateResponse(HttpStatusCode.OK,
                                    new
                                    {
                                        id = inputFile.Id,
                                        isValid,
                                        details,
                                        hasMissingUniverseSheet = false,
                                        hasMissingUniverseSheetData = false
                                    });
                            }
                        }
                        catch (Exception ex)
                        {
                            log.Exception(ex);
                            return Request.CreateResponse(HttpStatusCode.InternalServerError,
                                new {ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException});
                        }
                    });

                return (Task<HttpResponseMessage>)result;
            }
            catch (Exception ex)
            {
                log.Exception(ex);
                return (new Task<HttpResponseMessage>(() => Request.CreateResponse(HttpStatusCode.InternalServerError,
                    new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException })));
            }
        }

        [Route("")]
        public HttpResponseMessage Patch([FromBody] InputFilePatchOpDto patch)
        {
            var response = (HttpResponseMessage)null;
            try
            {
                if (patch.Verb.ToUpper() == "PATCH" && patch.Canceled)
                {
                    var ok = _fileUpload.CancelInputFile(patch.ResourceId);

                    response = Request.CreateResponse(ok ? HttpStatusCode.NoContent : HttpStatusCode.InternalServerError);
                }
                else
                {
                    response = Request.CreateResponse(HttpStatusCode.NotImplemented, "Only support PATCH with Canceled = true");
                }
            }
            catch (ResourceNotFound ex)
            {
                log.Exception(ex);
                return Request.CreateResponse(HttpStatusCode.NotFound,
                                    new { ErrorStatusCode = WebAPIGeneralErrorCodes.ResourceNotFound, Input = patch });
            }
            catch (Exception ex)
            {
                log.Exception(ex);
                return Request.CreateResponse(HttpStatusCode.InternalServerError,
                                    new { ErrorStatusCode = WebAPIGeneralErrorCodes.UnhandledException, Input = patch });
            }
            return response;
        }

    }
}
